
/*************************************************************************
* Copyright (c) 2008, ShenZhen Coship Electronic Ltd Co.
* All rights reserved.
* 
* File Name:		XvidDecode.cpp
* Summary:			implementation for the CXvidDecode class.
* 
* Current Version:	1.1
* Author(s):
/------------------------------------------------------------------------/
revision			author				reason					date
1.0					Li Futang			Initialize Version		2008-5-29
1.1					Ding Ning			Modify data buffer		2008-6-18
/------------------------------------------------------------------------/
*************************************************************************/

#include "stdafx.h"
#include "XvidDecode.h"

#ifdef _RECORD_MPEG4_FILE
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <io.h>
#include <stdio.h>
#endif
//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////

//add by li futang 2008-05-29
CXvidDecode::CXvidDecode()
{
	m_bReversal = TRUE;
	m_hXvid = NULL;
	m_cType = CODEC_XVID;
	m_nWidth = 0;
	m_nHeight = 0;
	m_bInited = FALSE;
	m_pPic = NULL;
	m_pOut = NULL;
	m_pXvidData = NULL;
	m_nXvidDataSize = 0;

#ifdef _RECORD_MPEG4_FILE
	m_nFile = -1;
#endif
}

CXvidDecode::~CXvidDecode()
{
	Destroy();
}

void CXvidDecode::XGlobalInit()
{
	xvid_gbl_init_t   xvid_gbl_init;

	/* Reset the structure with zeros */
	memset(&xvid_gbl_init, 0, sizeof(xvid_gbl_init_t));
	
	/*------------------------------------------------------------------------
	 * XviD core initialization
	 *----------------------------------------------------------------------*/

	/* Version */
	xvid_gbl_init.version = XVID_VERSION;

		/* Assembly setting */
	/*	if(use_assembler)
	#ifdef ARCH_IS_IA64
		xvid_gbl_init.cpu_flags = XVID_CPU_FORCE | XVID_CPU_IA64;
	#else
		xvid_gbl_init.cpu_flags = 0;
	#endif
		else*/
	xvid_gbl_init.cpu_flags = XVID_CPU_FORCE;//| XVID_CPU_ASM ; // force to use asm optimized routine;

	xvid_gbl_init.debug = 0;//debug_level;

	xvid_global(NULL, XVID_GBL_INIT, &xvid_gbl_init, NULL);
}

BOOL CXvidDecode::Init(const char* pbuf, int len)
{
	//initial the codec
	if(!m_bInited) 
	{
		// modify by dingning 2008-6-18
		m_pDecBuf = new DecBuf((CircleBuf*)pbuf);
		m_pDecBuf->CreateObj();
// 		m_pDecBuf = NULL;

		int ret;
		xvid_dec_create_t xvid_dec_create;

		/* Reset the structure with zeros */
		memset(&xvid_dec_create, 0, sizeof(xvid_dec_create_t));

		/*------------------------------------------------------------------------
		 * XviD encoder initialization
		 *----------------------------------------------------------------------*/

		/* Version */
		xvid_dec_create.version = XVID_VERSION;

		/*
		 * Image dimensions -- set to 0, xvidcore will resize when ever it is
		 * needed
		 */
		xvid_dec_create.width = 0;
		xvid_dec_create.height = 0;

		ret = xvid_decore(NULL, XVID_DEC_CREATE, &xvid_dec_create, NULL);

		if(ret == 0)
		{
			m_hXvid = xvid_dec_create.handle;
			m_bInited = TRUE;
			m_nXvidDataSize = 720 * 576;
			m_pXvidData = new char[m_nXvidDataSize];
			if(!m_pXvidData)
			{
				m_nXvidDataSize = 0;
			}
		}
		else
		{
			SAFE_DELETE(m_pDecBuf);
			return FALSE;
		}
	}

	return TRUE;
}


void CXvidDecode::Destroy()
{
	if(m_hXvid)
	{
		xvid_decore(m_hXvid, XVID_DEC_DESTROY, NULL, NULL);
		m_hXvid = NULL;
	}	
	SAFE_DELETE(m_pDecBuf);
	SAFE_DELETE(m_pPic);
	SAFE_DELETE(m_pOut);
	SAFE_DELETE(m_pXvidData);
	m_nXvidDataSize = 0;

#ifdef _RECORD_MPEG4_FILE
	if(-1 != m_nFile)
	{
		_close(m_nFile);
		m_nFile = -1;
	}
#endif
}

BOOL CXvidDecode::Decode(const char* pbuf, int len, int subLen)
{
	xvid_dec_frame_t xvid_dec_frame;
	xvid_dec_stats_t xvid_dec_stats;
	/* Reset all structures */
	memset(&xvid_dec_frame, 0, sizeof(xvid_dec_frame_t));
	memset(&xvid_dec_stats, 0, sizeof(xvid_dec_stats_t));
	
	/* Set version */
	xvid_dec_frame.version = XVID_VERSION;
	xvid_dec_stats.version = XVID_VERSION;

	/* No general flags to set */
	xvid_dec_frame.general          = 0;

	/* Input stream */
	// modify by dingning 2008p-6-18
// 	unsigned char* xviddata			= new unsigned char[m_pDecBuf->GetCir()->GetStock()];
// 	int istream_size				= m_pDecBuf->GetCir()->Read(xviddata, m_pDecBuf->GetCir()->GetStock());
/*
	int istream_size				= m_pDecBuf->GetCir()->GetStock();
	if (istream_size == 0)
		return FALSE;
	unsigned char* xviddata			= NULL;
	xviddata						= new unsigned char[istream_size];
	m_pDecBuf->GetCir()->Read(xviddata, istream_size);
*/

/*
	unsigned char* xviddata			= (unsigned char*)pbuf;
	int istream_size				= len;
*/
// 	unsigned char* xviddata			= new unsigned char[len];
// 	int istream_size				= len;
// 	memcpy(xviddata, pbuf, len);

	int datasize					= m_pDecBuf->GetCir()->GetStock();
	if(datasize <= 0)
	{
		return FALSE;
	}

	if(m_nXvidDataSize < datasize)
	{
		SAFE_DELETE(m_pXvidData);
	}
	if(!m_pXvidData)
	{
		m_nXvidDataSize = datasize > 720 * 576 ? datasize : 720 * 576;
		m_pXvidData = new char[m_nXvidDataSize];
		if(!m_pXvidData)
		{
			m_nXvidDataSize = 0;
			ATLTRACE("FAILED: CXvidDecode::Decode allocate mem failed size = %d\n", datasize);
			return FALSE;
		}
	}

	ATLASSERT(m_nXvidDataSize >= m_pDecBuf->GetCir()->GetStock());
	int nReadSize = m_pDecBuf->GetCir()->GetStock();
	nReadSize = nReadSize <= m_nXvidDataSize ? nReadSize : m_nXvidDataSize;
	int istream_size				= m_pDecBuf->GetCir()->Read(m_pXvidData, nReadSize);
#ifdef _RECORD_MPEG4_FILE
		if(-1 == m_nFile)
		{
			char buf[MAX_PATH];
			SYSTEMTIME systime;
			GetLocalTime(&systime);

			sprintf(buf, "C:\\%02d%02d%02d%03d.mpeg4", systime.wHour, systime.wMinute, systime.wMinute, systime.wMilliseconds);
			m_nFile = _open(buf, _O_CREAT | _O_BINARY | _O_RDWR,  _S_IREAD | _S_IWRITE);
		}
		if(-1 != m_nFile)
		{
			//DWORD dwlen = nReadSize;
			//_write(m_nFile, &dwlen, sizeof(DWORD));
			_write(m_nFile, m_pXvidData, nReadSize);
			long nfilesize = _tell(m_nFile);
			if(nfilesize > 1024 * 1024 * 200)
			{
				_close(m_nFile);
				m_nFile = -1;
			}
		}
#endif	
	xvid_dec_frame.bitstream        = m_pXvidData;
	xvid_dec_frame.length           = istream_size;

	/* Output frame structure */
	//CSP = XVID_CSP_YV12;
	//BPP = 1;
	xvid_dec_frame.output.plane[0]  = m_pOut;
	xvid_dec_frame.output.stride[0] = m_nWidth*1;
	xvid_dec_frame.output.csp = XVID_CSP_YV12;
	
	if (m_pPic == NULL)
	{
		m_pPic = new PicInfo();
		m_pPic->BpS = 0;
		m_pPic->Height = 0;
		m_pPic->Width = 0;
	}
	int decodelen = 0;
	try
	{
		decodelen = xvid_decore(m_hXvid, XVID_DEC_DECODE, &xvid_dec_frame, &xvid_dec_stats);
		if(xvid_dec_stats.type == XVID_TYPE_VOL) 
		{
			/* Check if old buffer is smaller */
			if(m_nWidth*m_nHeight < xvid_dec_stats.data.vol.width*xvid_dec_stats.data.vol.height) 
			{

				/* Copy new witdh and new height from the vol structure */
				m_nWidth = xvid_dec_stats.data.vol.width;
				m_nHeight = xvid_dec_stats.data.vol.height;

				/* Free old output buffer*/
				SAFE_DELETE(m_pOut);

				/* Allocate the new buffer */
				m_pOut = new unsigned char[m_nWidth*m_nHeight*4];
				//need to assuse m_pOut>NULL
			}
			if(decodelen<istream_size) // there are i frame data in the buffer
			{
				xvid_dec_frame.bitstream        = m_pXvidData + decodelen;
				xvid_dec_frame.length           = istream_size - decodelen;

				xvid_dec_frame.output.plane[0]  = m_pOut;
				xvid_dec_frame.output.stride[0] = m_nWidth*1;
				xvid_dec_frame.output.csp = XVID_CSP_YV12;

				decodelen = xvid_decore(m_hXvid, XVID_DEC_DECODE, &xvid_dec_frame, &xvid_dec_stats);
			}
		}
	}
	catch(...)
	{
		ATLTRACE("EXCEPT: CXvidDecode::Decode\n");
	}

	if (decodelen > 0 && xvid_dec_stats.type > 0)
	{
		m_pPic->BpS = m_nWidth;
		m_pPic->Height = m_nHeight;
		m_pPic->Width = m_nWidth;
		m_pPic->Y = m_pOut;
		m_pPic->V = m_pOut + m_nHeight*m_nWidth;
		m_pPic->U = m_pOut + m_nHeight*m_nWidth*5/4;

		return TRUE;
	}
	else
	{
		SAFE_DELETE(m_pPic);
	}
	return FALSE;
}

void CXvidDecode::InitPicInfo()
{
	//GetVideoSize(m_hXvid, &m_nWidth, &m_nHeight);
	return;
}

//end
